require'zdc.errdef'
local floor=math.floor
local getdoc=require'zdc.doc'.get_doc
local type=type
local numbit=require'zdc.numbit'
local bitapi_band=require 'bit'.band
module(..., package.seeall)

function InstallType(t,mod)
	mod=mod or _M
	if type(mod)=='string' then mod=require'mod' end
	for k,v in pairs(mod) do
		if type(v)=='table' and v.name then
			t[k]=v
		end
	end
end

function GetShowVal(t,val)
	local s=t and t._showS
	if s then return s(t,val) end
	return val
end

function GetTypeHelp(t,l,pre)
	local _helpU=t._helpU
	if _helpU then return _helpU(t,l,pre) end
	if l and type(l)~='string' then l=tostring(l) end
	return nil,{'<' .. (t.memo or t.name) ..'>\t' .. (l or '')};
end

function GetTypeDoc(t)
	local hu
	if t._helpU then _,hu=t:_helpU() end
	return getdoc(t,'disp'),getdoc(t,'desc'),getdoc(t,'exam'), hu
end
local _typemetaneed={
name=0,
disp=1,
desc=2,
exam=2,
_class=1,
_map=1,
_doc=1,
}
function GetTypeMeta(vb,t)
	if not t then return nil end
	local m={}
	for k,v in pairs(t) do
		local chk=_typemetaneed[k]
		if chk and chk<=vb then
			m[k]=t[k]
		end
	end
	return m
end

NOTYPE={name='NOTYPE'}
function NOTYPE:_validU(val,limit)
	return true,val
end

function NOTYPE:_showS(val)
	return val
end

local ENUMHELP={_class='enum'}
local ENUMHELP_mt = {__index = function(t,k)
	return t._map[k] or  ENUMHELP[k]
end 
}
function ENUMHELP:_enumval(k)
	return self._map[k]
end
function ENUMHELP:_helpU(l,rest)
	-- TODO: limit support?
	rest=rest or ''
	local m={}
	local _map=self._map
	for k,v in pairs(_map) do
		if string.find(k,rest,1,true)==1 and (not l or self:_validU(k,l)) then
			m[#m+1]=k
		end
	end
	local l=#m
	table.sort(m,function(a,b) return _map[a]<_map[b] end)
	local v
	if l==0 then
		return nil,m
	elseif l==1 then
		v=m[1]
	end
	if (self._doc) then
		local _doc=self._doc
		for k,v in ipairs(m) do
			local d=getdoc(_doc[v],'disp')
			local d2=getdoc(_doc[v],'desc')
			if d then m[k]={v,d,d2} end
		end
	end
	return v,m
end
function ENUMHELP:_validU(val,limit)
	if val == nil then return false,'EBAT1:nil for enum ' .. self.name end
	val = tonumber(val) or val
	if type(val)=='number' then val= self._rmap[val] end
	local t = self._map[val]
	if t~=nil then
		if limit then
			if type(limit)=='table' then
				if limit[val] then return true,t end
				for _,k in ipairs(limit) do
					if val==k then return true,t end
				end
				return false,'EBAT1:' .. tostring(val) .. ' not in limit{' .. table.concat(limit,',') .. '} for enum ' .. self.name
			end
			if type(limit)=='function' then return limit(self,val) end
			return false,'EUL1:' .. tostring(limit) .. ' for enum ' .. self.name
		end
		return true,t 
	end
	return false,'EBV'
end

function ENUMHELP:_showS(val)
	if type(val)=='string' then return val end
	local t = self._rmap[val]
	if t~=nil then return t else return val end
end
local function getrmapfrommap(m)
	local rm={}
	for k,v in pairs(m) do
		rm[v]=k
	end
	return rm
end
local function bind_enum(t)
	t._rmap=t._rmap or getrmapfrommap(t._map)
	return setmetatable(t,ENUMHELP_mt)
end
GenENUM=function(name)
	return function (map)
		local t=bind_enum{name=name,_map=map}
		_M[name]=t
		return t
	end
end
GenENUMDOC=function(name)
	local t=_M[name]
	assert(type(t)=='table',"can't find enum " .. name)
	return function (map)
		t._doc=map
		return t
	end
end

GenENUM_NS=function(mod,name)
	return function (map)
		local t=bind_enum{name=name,_map=map}
		mod[name]=t
		return t
	end
end
GenENUMDOC_NS=function(mod,name)
	local t=mod[name]
	assert(type(t)=='table',"can't find enum " .. name)
	return function (map)
		t._doc=map
		return t
	end
end
GenENUM_NS_DOC=function(mod,name)
	local t=mod[name]
	assert(mod[name]==nil, "enum redefined: " .. name)
	return function (map)
		local enummap={}
		local docmap={}
		for k,v in pairs(map) do
			if not v.disp then
				v.disp=k
			end
			enummap[k]=v.v
			docmap[k]=v
		end
		local t=bind_enum{name=name,_map=enummap}
		mod[name]=t
		t._doc=docmap
		return t
	end
end

function TypeDef(old,name)
	local t = setmetatable({name=name},{__index=old})
	return t
end

STR={name='STR',_class='string',disp=[[string type]],desc=[[
limit support 3 format:
1. 'x-y' length must >=x and <=y, such as '1-4', '-5', '10-'
2. lua string match, ref to lua manule
3. user define function
]]}
function STR:_validU(val,limit)
	if type(val) ~= 'string' then return nil,'EBAT1:'..type(val) .. ' for TXT' end
	if limit then
		if type(limit)=='string' then
			local _l,_r=string.match(limit,'(%d*)-(%d*)')
			if _l then
				local len=#val
				_l=tonumber(_l)
				if _l and (len < _l) then return nil,'ESL1NI2:'..len..'`'..limit end
				_r=tonumber(_r)
				if _r and (len > _r) then return nil,'ESL1NI2:'..len..'`'..limit end
				return true,val
			else
				if string.find(val,limit) then return true,val end
				return nil,'ES1NM2:'..val..'`'..limit
			end
		end
		if type(limit)=='function' then return limit(self,val) end
		return nil,'EUL1:' .. tostring(limit)
	end
	return true,val
end

TXT=TypeDef(STR,'TXT')
BDATA=TypeDef(STR,'BDATA')

BOOL={name='BOOL',_class='boolean',desc=[[
boolean value: true or false
]]}
function BOOL:_validU(val)
	if val=='true' then return true,true end
	if val=='false' then return true,false end
	if type(val) ~= 'boolean' then return nil,'EBAT1:'..type(val) .. ' for BOOL' end
	return true,val
end
function BOOL:_showS(val)
	if val then return 'true' else return 'false' end
end

local function int_validU(obj, val, limit)
	if type(limit)=='string' then
		for sub in string.gmatch(limit,'[^|]+') do
			local s=tonumber(sub)
			if s then
				if val==s then return true,val end
			else
				local _la,_l,_r,_ra=string.match(sub,'([%(%[])(-?%d*),(-?%d*)([%)%]])')
				if _la then
					_l,_r = tonumber(_l),tonumber(_r)
					if val < _l or val > _r or (val==_l and _la=='(') or (val==_r and _ra==')') then
					else
						return true,val
					end
				end
			end
		end
		return nil,'EN1NI2:'..val..'`'..limit
	end
	if type(limit)=='function' then return limit(obj,val) end
	return nil,'EUL1:' .. tostring(limit)
end
INTEGER={name='INTEGER',_class='number',desc="unlimited integer"}
function INTEGER:_validU(val,limit)
	if type(val)=='string' then val=tonumber(val) end
	if type(val) ~= 'number' or val~=floor(val) then return false,'nil:'..type(val) .. ' for INTEGER' end
	if limit then
		return int_validU(self, val, limit)
	end
	return true,val
end
local function num_validU(obj, val, limit)
	if type(limit)=='string' then
		for sub in string.gmatch(limit,'[^|]+') do
			local s=tonumber(sub)
			if s then
				if val==s then return true,val end
			else
				local _la,_l,_r,_ra=string.match(sub,'([%(%[])(-?%d+%.?%d*),(-?%d+%.?%d*)([%)%]])')
				if _la then
					_l,_r = tonumber(_l),tonumber(_r)
					if val < _l or val > _r or (val==_l and _la=='(') or (val==_r and _ra==')') then
					else
						return true,val
					end
				end
			end
		end
		return nil,'EN1NI2:'..val..'`'..limit
	end
	if type(limit)=='function' then return limit(obj,val) end
	return nil,'EUL1:' .. tostring(limit)
end
NUMBER={name='NUMBER',_class='number',desc="unlimited number"}
function NUMBER:_validU(val,limit)
	if type(val)=='string' then val=tonumber(val) end
	if type(val) ~= 'number' then return false,'nil:'..type(val) .. ' for NUMBER' end
	if limit then
		return num_validU(self, val, limit)
	end
	return true,val
end

TIMESTAMP={name='TIMESTAMP',_class='number',desc=[[
timestamp value: seconds from 1970.1.1
]]}
function TIMESTAMP:_validU(val,limit)
	if type(val)=='string' then val=tonumber(val) end
	if type(val) ~= 'number' or val~=floor(val) then return false,'nil:'..type(val) .. ' for INTEGER' end
	if limit then
		return int_validU(self, val, limit)
	end
	return true,val
end
function TIMESTAMP:_showS(val)
	return os.date("%Y-%m-%d %H:%M:%S", tonumber(val)or 0)
end

TIMESTAMPMS={name='TIMESTAMPMS',_class='number',desc=[[
timestampms value: milliseconds from 1970.1.1
]]}
function TIMESTAMPMS:_validU(val,limit)
	if type(val)=='string' then val=tonumber(val) end
	if type(val) ~= 'number' or val~=floor(val) then return false,'nil:'..type(val) .. ' for INTEGER' end
	if limit then
		return int_validU(self, val, limit)
	end
	return true,val
end
function TIMESTAMPMS:_showS(val)
	local ms=tonumber(val) or 0
	return string.format("%s.%03d",os.date("%Y-%m-%d %H:%M:%S", ms/1000),ms%1000)
end

REFID={name='REFID',_class='string',desc=[[
REFID value: node id for reference
]]}
function REFID:_validU(val,limit)
	if type(val)~='string' then return nil,'EBAT1:'..type(val) .. ' for REFID' end
	if limit then
		if type(limit)=='function' then return limit(self,val) end
		return nil,'EUL1:' .. tostring(limit)
	end
	return true,val
end
function REFID:_showS(val)
	return val
end

DELTAID={name='DELTAID',_class='string',desc=[[
DELTAID value: node id for reference, but it is detla from a base path
]]}
function DELTAID:_validU(val,limit)
	if type(val)~='string' then return nil,'EBAT1:'..type(val) .. ' for DELTAID' end
	if limit then
		if type(limit)=='function' then return limit(self,val) end
		return nil,'EUL1:' .. tostring(limit)
	end
	return true,val
end
function DELTAID:_showS(val)
	return val
end

function DeltaidToRefid(n,fd,k)
	local base=fd.delta
	local dk=n[k]
	if #dk>0 then
		return ((base and n[base]) or fd.path or n[k .. 'Base'] or n[k:sub(1,3) .. 'Base']) .. '/' .. dk
	else
		return nil
	end
end

REFIDLST={name='REFIDLST',_class='string',desc=[[
REFIDLST value: node id list for reference
such as: "idpath[a/b,m,a/b/c];idref;idpath2[a[m,n],b,c]"
]]}
function REFIDLST:_validU(val,limit)
	if type(val)~='string' then return nil,'EBAT1:'..type(val) .. ' for REFIDLST' end
	if limit then
		if type(limit)=='function' then return limit(self,val) end
		return nil,'EUL1:' .. tostring(limit)
	end
	return true,val
end
function REFIDLST:_showS(val)
	return val
end

function RefidlstToTable(val,tv)
	tv= tv or {}
	if type(val)~='string' then return tv end
	for sub in string.gmatch(val,'[^;]+') do
		local pid,sid=string.match(sub,"^([^[]+)(%b[])")
		if pid then
			for ss in string.gmatch(string.sub(sid,2,#sid-1),'[^,]+') do
				table.insert(tv,pid..'/'..ss)
			end
		else
			table.insert(tv,sub)
		end
	end
	return tv
end

function RefidClone(val,from,to)
	if type(val)~='string' then return val end
	if val==from then return to end
	local nv=zdc.idutil.PreRemove(val,from)
	if nv then return to..nv end
	return val
end

function DeltaidClone(n,fd,k,from,to)
--TODO: not needed maybe
end

function RefidlstClone(val,from,to)
	if type(val)~='string' then return val end
	local nv=''
	for sub in string.gmatch(val,'[^;]+') do
		local pid,sid=string.match(sub,"^([^[]+)(%b[])")
		if pid then
			local npid=RefidClone(pid,from,to)
			
			if npid==pid then
				if zdc.idutil.IsRoot(pid,from) then
					local tv={}
					for ss in string.gmatch(string.sub(sid,2,#sid-1),'[^,]+') do
						local vl=RefidClone(pid..'/'..ss,from,to)
						table.insert(tv,vl)
					end
					nv=nv..((#nv>0 and ';')or'') .. table.concat(tv,';')
				else
					nv=nv..((#nv>0 and ';')or'') .. sub
				end
			else
				nv=nv..((#nv>0 and ';')or'') ..npid..sid
			end
		else
			nv=nv..((#nv>0 and ';')or'')..RefidClone(sub,from,to)
		end
	end
	return nv
end

require'zdc.fieldutil'

function AdjustRefid(n,from,to)
	local tb={}
	local fds=n._fds
	for k,v in pairs(fds) do
		local val=n[k]
		if val then
			local t=v[2]
			t=t and t.name
			if t=='REFID' then
				local nn=RefidClone(val,from,to)
				if nn~=val then
					n:__set_raw(k,nn)
					tb[k]=val
				end
			elseif t=='REFIDLST' then
				n:__set_raw(k,RefidlstClone(val,from,to))
				tb[k]=val
			end
		end
	end
	for k,val in pairs(n.__raw_v) do
		if not fds[k] then
			if not m or string.match(k,m) then
				local fd=zdc.fieldutil.dfskey(n._dfs,k)
				if fd then
					local t=fd[2]
					t=t and t.name
					if t=='REFID' then
						local nn=RefidClone(val,from,to)
						if nn~=val then
							n:__set_raw(k,nn)
							tb[k]=val
						end
					elseif t=='REFIDLST' then
						n:__set_raw(k,RefidlstClone(val,from,to))
						tb[k]=val
					end
				end
			end
		end
	end
	return tb
end

------------net type

MACADDR={name='MACADDR',_class='number',desc=[[
格式为：HHHH.HHHH.HHHH ,其中H为十六进制的数
limit 格式有：
1.'NM' 地址为非多播地址
2.'NB' 地址为非广播播地址
3.范围限制:'lHHHH.lHHHH.lHHHH-rHHHH.rHHHH.rHHHH' 例如：'0000.0000.0000-0000.1111.2222'
保存为数字形式:AAAA.BBBB.CCCC 对应0xAAAABBBBCCCC
]]}
function MACADDR:_showS(val)	
	if type(val) == 'number' then
		local w1,w2,w3=numbit.to_w3_4b(val)
		return string.format("%04x.%04x.%04x",w3,w2,w1)
	else
		return tostring(val)
	end
end

function MACADDR:_validU(val,limit)
	if type(val)=='number' then val=self:_showS(val) end
	if type(val) ~= 'string' then return false,'EBAT1:'..type(val) .. ' for MACADDR' end
	local a,b,c=string.match(val,'^(%w+)%.(%w+)%.(%w+)$')	
	if not a or not b or not c then return false,'EBMAF' .. val end
	if 4 ~= string.len (a)  or 4 ~= string.len (b) or 4 ~= string.len (c) then
		return false,'EBMAF' 
	end	
	a = tonumber(a,16)
	b = tonumber(b,16)
	c = tonumber(c,16)	
	if not a  or not b or not c then
		return false,'EBMAF' 
	end	 
	if (a) > 0xffff or (b) > 0xffff or  (c) > 0xffff then 
		return false,'EBMAF' 
	end
	
	local vali=numbit.from_w3_4b(c,b,a,0)
	if limit  then
--		if (a) == 0 and (b) == 0 and  (c) == 0 then
--			return false,'EBMAF' 
--		end
		if limit == 'NM' then
			if bitapi_band(a,0x0100) == 0x0100 then
				return false,'EMA1NI2:'..val..'`'..limit
			else
				return true,vali
			end 
		end
		if limit == 'NB' then
			if ((a) == 0xffff ) and  ((b) == 0xffff) and  ( (c) == 0xffff) then
				return false,'EMA1NI2:'..val..'`'..limit
			else
				return true,vali
			end
		end
		if type(limit)=='string' then
			local la,lb,lc,ra,rb,rc = string.match(limit,'^(%w+)%.(%w+)%.(%w+)-(%w+)%.(%w+)%.(%w+)$')
			if a >=tonumber(la,16) and a <= tonumber(ra,16) and  
				b >=tonumber(lb,16) and b <= tonumber(rb,16) and
				c >=tonumber(lc,16) and c <= tonumber(rc,16) then
				return true,vali
			else
				return false,'EMA1NI2:'..val..'`'..limit
			end
		end
		if type(limit)=='function' then return limit(self,val) end
		return false,'EUL1:' .. tostring(limit)
	end
	return true,vali
end

IPADDR={name='IPADDR',_class='number',desc=[[
格式为：A.B.C.D ,其中A、B、C、D为0－255十进制数字
limit 格式有：
1.'A' 地址为A类IP地址
2.'B' 地址B类IP地址
3.'C' 地址为C类IP地址
4.'D' 地址为D类IP地址
5.'ND' 地址为非D类IP地址
6.范围限制:'la.lb.lc.ld-ra.rb.rc.rd' 例如：'10.10.10.1-192.168.1.1'
保存为数字形式:AA.BB.CC.DD(A,B,C,D为16进制)对应0xAABBCCDD
]]}
function IPADDR:_showS(val)	
	if type(val) == 'number' then
		local b4,b3,b2,b1=numbit.to_b6_4b(val)
		return string.format("%d.%d.%d.%d",b1,b2,b3,b4)
	else
		return tostring(val)
	end
end
function IPADDR:_validU(val,limit)
	if type(val)=='number' then val=self:_showS(val) end
	if type(val) ~= 'string' then return false,'EBAT1:'..type(val) .. ' for APADDR' end
	local a,b,c,d=string.match(val,'^(%d+)%.(%d+)%.(%d+)%.(%d+)$')
	if not a or not b or not c or not d then
		return false,'EBIAF' 
	end
	a,b,c,d=tonumber(a),tonumber(b),tonumber(c),tonumber(d)
	if a > 255 or b > 255 or c > 255 or d > 255 then 
		return false,'EBIAF' 
	end
	local vali=numbit.from_b6_4b(d,c,b,a,0,0,0)
	if limit  then
		local v =a*0x01000000+b*0x00010000+c*0x00000100+d
		if limit == 'A' then
			local l,r = 1*0x01000000+1,126*0x01000000+255*0x00010000+0x00000100*255+254
			if v >= l and v <= r then
				return true,vali
			else
				return false,'EIA1NI2:'..val..'`'..'A Class range [1.0.0.1-126.255.255.254]'
			end
		end
		if limit == 'B' then
			local l,r = 128*0x01000000+1,191*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=1 and v < r then
				return true,vali
			else
				return false,'EIA1NI2:'..val..'`'..'B Class range [128.0.0.1-191.255.255.254]'
			end
		end
		if limit == 'C' then
			local l,r = 192*0x01000000+1,223*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=1 and v < r then
				return true,vali
			else
				return false,'EIA1NI2:'..val..'`'..'C Class range [192.0.0.1-223.255.255.254]'
			end
		end
		if limit == 'D' then
			local l,r = 224*0x01000000+1,239*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=1 and v < r then
				return true,vali
			else
				return false,'EIA1NI2:'..val..'`'..'D Class range [224.0.0.1-239.255.255.254]'
			end
		end
		if limit == 'ND' then
			local la,ra = 1*0x01000000+1,126*0x01000000+255*0x00010000+0x00000100*255+254
			local lb,rb = 128*0x01000000+1,191*0x01000000+255*0x00010000+0x00000100*255+254
			local lc,rc = 192*0x01000000+1,223*0x01000000+255*0x00010000+0x00000100*255+254
			if (v >= la and v <= ra) or 
				(v >= lb and v <= rb) or 
				(v >= lc and v <= rc) then
				return true,vali
			else
				return false,'EIA1NB2:'..val..'`'..' Not A||B||C Class'
			end
		end		
		if type(limit)=='string' then
			local la,lb,lc,ld,ra,rb,rc,rd = string.match(limit,'^(%d+)%.(%d+)%.(%d+)%.(%d+)-(%d+)%.(%d+)%.(%d+)%.(%d+)$')
			local l = tonumber(la)*0x01000000+tonumber(lb)*0x00010000+tonumber(lc)*0x00000100+tonumber(ld)
			local r = tonumber(ra)*0x01000000+tonumber(rb)*0x00010000+tonumber(rc)*0x00000100+tonumber(rd)
			if v >=l and v < r then 
				return true,vali
			else
				return false,'EIA1NI2:'..val..'`'..limit
			end
		end		
		if type(limit)=='function' then return limit(self,val) end
		return false,'EUL1:' .. tostring(limit)
	end	
	return true,vali
end

IPPREFIX={name='IPPREFIX',desc=[[
格式为：A.B.C.D/masklen ,其中A、B、C、D为0－255十进制数字
limit 格式有：
1.'A' 地址为A类IP地址
2.'B' 地址B类IP地址
3.'C' 地址为C类IP地址
4.'D' 地址为D类IP地址
5.'ND' 地址为非D类IP地址
保存为数字形式:AA.BB.CC.DD\MM(A,B,C,D,M为16进制)对应0xMMAABBCCDD
]]}
function IPPREFIX:_showS(val)	
	if type(val) == 'number' then
		local b4,b3,b2,b1,p=numbit.to_b6_4b(val)
		return string.format("%d.%d.%d.%d\\%d",b1,b2,b3,b4,p)
	else
		return tostring(val)
	end
end
function IPPREFIX:_validU(val,limit)
	if type(val)=='number' then val=self:_showS(val) end
	if type(val) ~= 'string' then return false,'bad type' end
	local a,b,c,d,p=string.match(val,'^(%d+)%.(%d+)%.(%d+)%.(%d+)[%/%\\](%d+)$')
	if not a or not b or not c or not d or not p then
		return false,'EBIPF'
	end
	a,b,c,d,p=tonumber(a),tonumber(b),tonumber(c),tonumber(d),tonumber(p)
	if a > 255 or b > 255 or c > 255 or d > 255  or p >32  or p==0 then 
		return false,'EBIPF'
	end
	local vali=numbit.from_b6_4b(d,c,b,a,p,0,0)
	if limit  then
		local v = tonumber(a)*0x01000000+tonumber(b)*0x00010000+tonumber(c)*0x00000100+tonumber(d)
		if limit == 'A' then
			local l,r = 1*0x01000000+1,126*0x01000000+255*0x00010000+0x00000100*255+254			
			if v >=l and v < r and 
				tonumber(d) >=8 and tonumber(d) <= 32 then
				return true,vali
			else
				return false,'EIP1NI2:'..val..'`'..'A Class range [1.0.0.1-126.255.255.254]'
			end
		end
		if limit == 'B' then
			local l,r = 128*0x01000000+1,191*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=l and v < r and 
				tonumber(p) >=16 and tonumber(d) <= 32 then
				return true,vali
			else
				return false,'EIP1NI2:'..val..'`'..'B Class range [128.0.0.1-191.255.255.254]'
			end
		end
		if limit == 'C' then
			local l,r = 192*0x01000000+1,223*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=l and v < r and  
				tonumber(p) >=24 and tonumber(d) <= 32 then
				return true,vali
			else
				return false,'EIP1NI2:'..val..'`'..'C Class range [192.0.0.1-223.255.255.254]'
			end
		end
		if limit == 'D' then
			local l,r = 224*0x01000000+1,239*0x01000000+255*0x00010000+0x00000100*255+254
			if v >=l and v < r  then
				return true,vali
			else
				return false,'EIP1NI2:'..val..'`'..'D Class range [224.0.0.1-239.255.255.254]'
			end
		end
		if limit == 'ND' then
			local la,ra = 1*0x01000000+1,126*0x01000000+255*0x00010000+0x00000100*255+254
			local lb,rb = 128*0x01000000+1,191*0x01000000+255*0x00010000+0x00000100*255+254
			local lc,rc = 192*0x01000000+1,223*0x01000000+255*0x00010000+0x00000100*255+254
			if (v >= la and v <= ra and tonumber(p) >= 1 and tonumber(p) <= 32) or  
				(v >= lb and v <= rb and tonumber(p) >= 1 and tonumber(p) <= 32) or  
				(v >= lc and v <= rc and tonumber(p) >= 1 and tonumber(p) <= 32) then
				return true,vali
			else
				return false,'EIP1NB2:'..val..'`'..'D Class'
			end
		end		
		if type(limit)=='string' then
			local la,lb,lc,ld,ra,rb,rc,rd = string.match(limit,'^(%d+)%.(%d+)%.(%d+)%.(%d+)-(%d+)%.(%d+)%.(%d+)%.(%d+)$')
			local l = tonumber(la)*0x01000000+tonumber(lb)*0x00010000+tonumber(lc)*0x00000100+tonumber(ld)
			local r = tonumber(ra)*0x01000000+tonumber(rb)*0x00010000+tonumber(rc)*0x00000100+tonumber(rd)
			if v >=l and v < r then
				return true,vali
			else
				return false,'EIP1NI2:'..val..'`'..limit
			end
		end		
		if type(limit)=='function' then return limit(self,val) end
		return false,'EUL1:' .. tostring(limit)
	end	
	return true,vali	
end